"""
A simple VTK interactor style to mimic JointTrack.


Created by bryan Conrad, December 2008
Based on vtkTkRenderWindget.py

"""

"""
Please see the example at the end of this file.

----------------------------------------
Creation:

wxVTKRenderWindow(parent, ID, stereo=0, [wx keywords]):

You should create a wxPySimpleApp() or some other wx**App
before creating the window.

----------------------------------------
Methods:

Render()
AddRenderer(ren)
GetRenderers()
GetRenderWindow()

----------------------------------------
Methods to override (all take a wxEvent):

OnButtonDown(obj,event)  default: propagate event to Left, Right, Middle
OnLeftDown(obj,event)    default: set _Mode to 'Rotate'
OnRightDown(obj,event)   default: set _Mode to 'Zoom'
OnMiddleDown(obj,event)  default: set _Mode to 'Pan'

OnButtonUp(obj,event)    default: propagate event to L, R, M and unset _Mode
OnLeftUp(obj,event)
OnRightUp(obj,event)
OnMiddleUp(obj,event)

OnMotion(obj,event)      default: call appropriate handler for _Mode

OnEnterWindow(obj,event) default: set focus to this window
OnLeaveWindow(obj,event) default: release focus

OnKeyDown(obj,event)     default: [R]eset, [W]irefreme, [S]olid, [P]ick
OnKeyUp(obj,event)
OnChar(obj,event)

OnSetFocus(obj,event)
OnKillFocus(obj,event)

OnSize(obj,event)
OnMove(obj,event)

OnPaint(obj,event)       default: Render()

----------------------------------------
Protected Members:

_Mode:                 Current mode: 'Rotate', 'Zoom', 'Pan'
_LastX, _LastY:        The (x,y) coordinates of the previous event
_CurrentRenderer:      The renderer that was most recently clicked in
_CurrentCamera:        The camera for the current renderer

----------------------------------------
Private Members:

__Handle:              Handle to the window containing the vtkRenderWindow

"""

# import usual libraries
from math import sqrt, pow, atan2
from numpy import zeros, ones, cross
import numpy as np
import string
import logging
import os
import sys
import time
import vtk
from JT.QVTKRenderWindowInteractor import * 
import JT

# QT codes for directions keys
LEFT = 16777234
RIGHT = 16777236
UP = 16777235
DOWN = 16777237

class JTInteractorStyle(vtk.vtkInteractorStyle):
    """
    A RenderWindowInteractorStyle for wxPython.
    Use GetRenderWindow() to get the vtkRenderWindow.
    Create with the keyword stereo=1 in order to
    generate a stereo-capable window.
    """
    def __init__(self, iren=None):
        # initialize with an interactor so that the callbacks can be set.
        self._iren = iren
        if self._iren == None:
            print "Debug: style initialized without interactor."
        else:
             #if the interactor was specified, then set the callbacks
            self._RenderWindow = self._iren.GetRenderWindow()
            self.SetCallbacks()

        # miscellaneous protected variables
        self._CurrentRenderer = None
        self._PickedRenderer = None

        self._CurrentCamera = None
        self._CurrentZoom = 1.0
        self._CurrentLight = None

        self._ViewportCenterX = 0
        self._ViewportCenterY = 0

        self._Picker = vtk.vtkPropPicker()
        self._vtkMath = vtk.vtkMath()
        self._PickedActor = None
        self._PickedProperty = vtk.vtkProperty()
        self._PickedProperty.SetColor(1,0,0)
        self._PrePickedProperty = None
        self._PickColor = (1,0,0)

        self._OutlineActor = None
        self._Outline = vtk.vtkOutlineSource()
        self._OutlineMapper = vtk.vtkPolyDataMapper()
        self._OutlineMapper.SetInput(self._Outline.GetOutput())

        self._keyboardStepSize = 1
        self._rotStepSize = 1
        self._motionFactor = 10 #VTK does not allow this property to be changed

        self._USE_X_CAPTURE = 0

        self._AutoAdjustCameraClippingRange = 0

        self._OffscreenWin2Img = None

        # these record the previous mouse position
        self._LastX = 0
        self._LastY = 0
        
        # the current interaction mode (Rotate, Pan, Zoom, etc)
        self._Mode = None
        self._ActiveButton = None

        # private attributes
        self.__OldFocus = None

        # used by the LOD actors
        self._DesiredUpdateRate = 1
        self._StillUpdateRate = 0.1
        

    def SetCallbacks(self):
#        self.RemoveAllObservers()
#        self._RenderWindow.RemoveAllObservers()
#        self._iren.RemoveAllObservers()
        self._iren.AddObserver("LeftButtonPressEvent", self._OnButtonDown)
        self._iren.AddObserver("LeftButtonReleaseEvent", self._OnButtonUp)
        self._iren.AddObserver("MiddleButtonPressEvent", self._OnButtonDown)
        self._iren.AddObserver("MiddleButtonReleaseEvent", self._OnButtonUp)
        self._iren.AddObserver("RightButtonPressEvent", self._OnButtonDown)
        self._iren.AddObserver("RightButtonReleaseEvent", self._OnButtonUp)
        #self._iren.AddObserver("MouseMoveEvent", self.OnMotion)
        self._iren.AddObserver("KeyPressEvent", self.OnKeyDown)
        self._iren.AddObserver("KeyReleaseEvent", self.OnKeyUp)
        self._iren.AddObserver("CharEvent", self.OnChar)
        
        self.AddObserver("LeftButtonPressEvent", self.doNothing)
        self.AddObserver("LeftButtonReleaseEvent", self.doNothing)
        self.AddObserver("MiddleButtonPressEvent", self.doNothing)
        self.AddObserver("MiddleButtonReleaseEvent", self.doNothing)
        self.AddObserver("RightButtonPressEvent", self.doNothing)
        self.AddObserver("RightButtonReleaseEvent", self.doNothing)
        #self.AddObserver("MouseMoveEvent", self.doNothing)
        self.AddObserver("KeyPressEvent", self.doNothing)
        self.AddObserver("KeyReleaseEvent", self.doNothing)
        self.AddObserver("CharEvent", self.doNothing)
    
    def doNothing(self,obj,event):
        pass

    def SetRenderWindowInteractor(self,iren):
        """
        Set the render window interactor, and associated render window (if any)
        """
        self._iren = iren
        self._RenderWindow = iren.GetRenderWindow()

    def SetRenderWindow(self,rw):
        self._RenderWindow = rw


    def SetDesiredUpdateRate(self, rate):
        """Mirrors the method with the same name in
        vtkRenderWindowInteractor."""
        self._DesiredUpdateRate = rate

    def GetDesiredUpdateRate(self):
        """Mirrors the method with the same name in
        vtkRenderWindowInteractor."""
        return self._DesiredUpdateRate

    def SetStillUpdateRate(self, rate):
        """Mirrors the method with the same name in
        vtkRenderWindowInteractor."""
        self._StillUpdateRate = rate

    def GetStillUpdateRate(self):
        """Mirrors the method with the same name in
        vtkRenderWindowInteractor."""
        return self._StillUpdateRate


    def _OnButtonDown(self,obj,event):
        # helper function for capturing mouse until button released
        self._RenderWindow.SetDesiredUpdateRate(self._DesiredUpdateRate)

        if event == "RightButtonPressEvent":
            button = "Right"
        elif event == "LeftButtonPressEvent":
            button = "Left"
        elif event == "MiddleButtonPressEvent":
            button = "Middle"
        else:
            button = None

        self.OnButtonDown(obj,event)

    def OnButtonDown(self,obj,event):
        if not self._Mode:
            # figure out what renderer the mouse is over
            self.UpdateRenderer(obj,event)
        if event == "LeftButtonPressEvent":
            self.OnLeftDown(obj,event)
        elif event == "RightButtonPressEvent":
            self.OnRightDown(obj,event)
        elif event == "MiddleButtonPressEvent":
            self.OnMiddleDown(obj,event)


    def OnLeftDown(self,obj,event):
        if not self._Mode:
            if obj.GetControlKey():
                self._Mode = "Zoom"
            elif obj.GetShiftKey():
                self._Mode = "Pan"
            else:
                self._Mode = "Rotate"

        self._iren.StartPickCallback()
        self._iren.EndPickCallback()

        self.PickActor(obj,event)


    def OnRightDown(self,obj,event):
        if not self._Mode:
            self._Mode = "Zoom"
            
    def OnMiddleDown(self,obj,event):
        if not self._Mode:
            self._Mode = "Pan"

    def _OnButtonUp(self,obj,event):
        # helper function for releasing mouse capture
        self._RenderWindow.SetDesiredUpdateRate(self._StillUpdateRate)

        if event == "RightButtonReleaseEvent":
            button = "Right"
        elif event == "LeftButtonReleaseEvent":
            button = "Left"
        elif event == "MiddleButtonReleaseEvent":
            button = "Middle"
        else:
            button = None

        # if the ActiveButton is realeased, then release mouse capture
        if self._ActiveButton and button == self._ActiveButton:
            if self._USE_X_CAPTURE:
                self.ReleaseMouse()
            self._ActiveButton = None

        self.OnButtonUp(obj,event)

    def OnButtonUp(self,obj,event):
        if event == "LeftButtonReleaseEvent":
            self.OnLeftUp(obj,event)
        elif event == "RightButtonReleaseEvent":
            self.OnRightUp(obj,event)
        elif event == "MiddleButtonReleaseEvent":
            self.OnMiddleUp(obj,event)

        # if not interacting, then do nothing more
        if self._Mode:
            if self._CurrentRenderer:
                self.Render()

        self._Mode = None

    def OnLeftUp(self,obj,event):
        pass

    def OnRightUp(self,obj,event):
        pass

    def OnMiddleUp(self,obj,event):
        pass

    def OnMotion(self,obj,event):
        self.HighlightProp3D(self._PickedActor)
        if self._Mode == "Pan":
            self.Pan()  #Default pan interaction
        elif self._Mode == "Rotate":
            self.Rotate(obj,event)  #Custom Rotate interaction
        elif self._Mode == "Zoom":
            self.Dolly(obj,event)    #Custom Dolly(zoom) interaction


    def OnChar(self,obj,event):
        pass

    def OnKeyDown(self,obj,event):
        # TODO: DEBUG
        #print "JTInteratorStyle object: %s" % event
        keysym = obj.GetKeySym()
        keycode = obj.GetKeyCode()
        # for QT, keysym is not set???
#        try:
#            keysym = self._iren._key
#        except:
#            pass
        # Change Keyboard Step size
        if (keycode == '-'):
            self._keyboardStepSize *= 0.6
            print "Keyboard step size: ", self._keyboardStepSize
            return
        elif keycode == '+':
            if ((self._keyboardStepSize / 0.6) < (self._RenderWindow.GetSize()[0]/2.0)):
                self._keyboardStepSize /= 0.6
            else:
                print "Keyboard step size limited to: ", self._RenderWindow.GetSize([0])/2.0
            print "Keyboard step size: ", self._keyboardStepSize
            return
        elif keycode == '=':   #seems only US keyboard has = and + on the same key.
            if ((self._keyboardStepSize / 0.6) < (self._RenderWindow.GetSize()[0]/2.0)):
                self._keyboardStepSize /= 0.6
            else:
                print "Keyboard step size limited to: ", self._RenderWindow.GetSize()[0]/2.0
            print "Keyboard step size: ", self._keyboardStepSize
            return

        # Reset Camera *** WARNING *** this could invalidate a calibration!
        elif keysym == 'r':
            #self.Reset(obj,event)
            print "Calibrated view cannot be reset"
            return
        
        # reset the center of rotation of the actor
        elif keycode == 'c':
            I = np.eye(4)
            orientation = self._PickedActor.GetOrientation()
            position = self._PickedActor.GetPosition()
            print "Original Position and Orientation: %s, %s" % (str(position),
                                                                 str(orientation))
            self._PickedActor.SetUserMatrix(JT.utils.GetVTKMatrixFromNumpyArray(I))
            self._PickedActor.SetOrientation(0,0,0)
            #self._PickedActor.SetPosition(0,0,0)
            center = np.asarray(self._PickedActor.GetCenter()) - \
                     np.asarray(self._PickedActor.GetPosition())
            self._PickedActor.SetOrigin(center)
            self._PickedActor.SetOrientation(orientation)
            self._PickedActor.SetPosition(center)
            print "Original Position and Orientation: %s, %s" % (str(self._PickedActor.GetPosition()),
                                                     str(self._PickedActor.GetOrientation()))
            #self._PickedActor.SetPosition(position)
            print "Reset center to: %s" % str(center)
            return

        # Pick actor under the cursor
        elif keysym == 'p':
            self.PickActor(obj,event)
            return

        # Close the render window
        elif keysym == 'e':
            print "Exiting with keypress e"
            self._iren.ExitCallback()
            #logging.debug('Exiting interaction with keypress: %s'%keysym)
            #

        # Some debug actions
        elif keysym =='d':
            if (self._iren.GetControlKey()):
                if self._PickedActor:
                    print "Actor: ", self._PickedActor
            else:
                print "Camera: ", self._CurrentCamera

        # Interactively change the volume color
        # This will only work for volume actors
        # 'l' alone will increase the set point, Ctrl+'l' will decrease
        elif keysym == 'l':
            if self._PickedActor != None:
                self.KeyboardSetOpacityLevel(self._iren.GetControlKey())

        # Interactively change the volume opacity
        # This will only work for volume actors
        # 'o' alone will increase the set point, Ctrl+'o' will decrease
        elif keysym == 't':
            if self._PickedActor != None:
                self.KeyboardSetOpacityThreshold(self._iren.GetControlKey())

        # Print Help
        elif keysym =='h':
            self.PrintHelp()

        # Keyboard interaction
        if self._PickedActor != None:
            if ((keysym == "Left") or (keysym == "Right") or (keysym == "Up") or (keysym == "Down")):
                if (self._iren.GetShiftKey()):
                    self.KeyboardZTransRotate()
                elif (self._iren.GetControlKey()):
                    self.KeyboardRotate()
                else:
                    self.KeyboardTranslate()

                #self.HighlightProp3D(self._PickedActor)

    def OnKeyUp(self,obj,event):
        pass

    def GetZoomFactor(self):
        return self._CurrentZoom

    def GetRenderWindow(self):
        return self._RenderWindow

    def GetPicker(self):
        return self._Picker

    def Render(self):
        self._iren.Render()

    def PrintHelp(self):
        print "Custom JointTrack Interaction Style"
        print ""
        print "Interaction mode is 'Actor' meaning that the camera is fixed in space"
        print "and all movements are applied to the picked actor"
        print "Keyboard Shortcuts"
        print "     Exit (e)"
        print "     Keyboard Step Size (+, -)"
        print "     Change opacity threshold (t)"
        print "     Change opacity level (l)"
        print "     Pick actor under cursor (p, or Left mouse click)"
        print "     Debug Info (d: camera, Ctrl+d: picked actor)"
        print "     Exit (e)"

    def KeyboardSetOpacityLevel(self,ctrl=False):
        """
        Set the color transfer function to alter display of image
        """
        actor = self._PickedActor

        if (ctrl==False):
            try:
                point = actor._otfLevel
                step = self._keyboardStepSize / 50.0
                point += step
            except:
                print "Could not set actor brightness"
                return
        else:
            try:
                point = actor._otfLevel
                step = self._keyboardStepSize / 50.0
                point -= step
            except:
                print "Could not set actor brightness"
                return
        #don't do anything if point is less than 1 or greater than 254
        if 0< point <1:
            actor.SetOpacityLevel(point)
            self.Render()
            print "Current Opacity Level (step): %f (%f)" % (point,step)
        else:
            print "Color SetPoint outside of visible range, nothing done."

    def KeyboardSetOpacityThreshold(self,ctrl=False):
        """
        Set the opacity transfer function to alter display of image
        """
        actor = self._PickedActor

        if (ctrl==False):
            try:
                point = actor._otfThreshold
                step = self._keyboardStepSize * 3
                point += step
            except:
                logging.debug("Could not set actor opacty")
                return
        else:
            try:
                point = actor._otfThreshold
                step = self._keyboardStepSize * 3
                point -= step
            except:
                logging.debug("Could not set actor opacity")
                return
            

        #don't do anything if point is less than 1 or greater than 254
        if 1< point:
            actor.SetOpacityThreshold(point)
            self.Render()
            print "Current Opacity Threshold (step): %f (%f)" % (point,step)
        else:
            logging.debug("Opacity Threshold outside of visible range, nothing done.")


    def UpdateRenderer(self,obj,event):
        """
        UpdateRenderer will identify the renderer under the mouse and set
        up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
        """
        x,y = obj.GetEventPosition()
        #TODO: Debug
        #print "in UpdateRenderer, event position (x,y):", x,y

        windowX, windowY = self._RenderWindow.GetSize()

        renderers = self._RenderWindow.GetRenderers()
        numRenderers = renderers.GetNumberOfItems()

        self._CurrentRenderer = None
        renderers.InitTraversal()
        for i in range(0,numRenderers):
            renderer = renderers.GetNextItem()
            vx,vy = (0,0)
            if (windowX > 1):
                vx = float(x)/(windowX-1)
            if (windowY > 1):
                vy = (windowY-float(y)-1)/(windowY-1)
            (vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()

            if (vx >= vpxmin and vx <= vpxmax and
                vy >= vpymin and vy <= vpymax):
                self._CurrentRenderer = renderer
                self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
                                        +vpxmin
                self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
                                        +vpymin
                self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
                lights = self._CurrentRenderer.GetLights()
                lights.InitTraversal()
                self._CurrentLight = lights.GetNextItem()
                break

        self._LastX = x
        self._LastY = y

    def GetCurrentRenderer(self):
        return self._CurrentRenderer

    def Rotate(self,obj,event):

        if ((self._CurrentRenderer == None) or (self._PickedActor == None)):
            return
        rwi = self._iren
        cam = self._CurrentRenderer.GetActiveCamera()

        # First get the origin of the assembly
        obj_center = self._PickedActor.GetCenter()

        # GetLength gets the length of the diagonal of the bounding box
        boundRadius = self._PickedActor.GetLength() * 0.5

        # Get the view up and view right vectors
        view_up = view_look = view_right = zeros(3)

        # The VTK docs say we don't need to call the next two lines, but they are in the JT code.
        cam.OrthogonalizeViewUp()
        cam.ComputeViewPlaneNormal()
        view_up = cam.GetViewUp()
        #The camera seems to normalize the vector internally anyway, not sure if this is necessary
        self._vtkMath.Normalize(view_up)
        view_look = cam.GetViewPlaneNormal()
        self._vtkMath.Cross(view_up,view_look,view_right)

        # Get the furtherest point from the oject position+origin
        outsidept = zeros(3)

        outsidept[0] = obj_center[0] + view_right[0] * boundRadius
        outsidept[1] = obj_center[1] + view_right[1] * boundRadius
        outsidept[2] = obj_center[2] + view_right[2] * boundRadius

        # Convert them to display coord
        disp_obj_center = zeros(3)

        self.ComputeWorldToDisplay(self._CurrentRenderer,
                                    obj_center[0], obj_center[1], obj_center[2], disp_obj_center)
        self.ComputeWorldToDisplay(self._CurrentRenderer,
                                    outsidept[0], outsidept[1], outsidept[2], outsidept)

        radius = sqrt(self._vtkMath.Distance2BetweenPoints(disp_obj_center,outsidept))

        # Prevent it from rotating too fast if the model is too small (too far away)
        if (radius < 50):
            radius = 50

        # Mouse Motion
        diff = zeros(2) # in display coordinates, Note y (diff[1]) is still upward in vtk convention
        diff[0] = rwi.GetEventPosition()[0] - rwi.GetLastEventPosition()[0]
        diff[1] = rwi.GetEventPosition()[1] - rwi.GetLastEventPosition()[1]

        diff_vector = zeros(3)
        diff_vector[0] = diff[0]*view_right[0] + diff[1]*view_up[0]
        diff_vector[1] = diff[0]*view_right[1] + diff[1]*view_up[1]
        diff_vector[2] = diff[0]*view_right[2] + diff[1]*view_up[2]

        rotate = [zeros(4), zeros(4)]   #Prop3DTransform expects a 2D matrix
        rot_axis = rotate[0][1:]
        self._vtkMath.Cross(view_look,diff_vector,rot_axis)
        diff_length = sqrt(diff[0]**2 + diff[1]**2)
        rotate[0][0] = diff_length / radius * 90 # in degrees

        scale = ones(3)
        self.Prop3DTransform(self._PickedActor,self._PickedActor.GetPosition(),
                             1,
                             rotate,
                             scale)

        self.Render()


    def KeyboardTranslate(self):
        if (self._CurrentRenderer==None):    #CurrentRenderer can be None if there were no mouse interaction before
            self.FindPokedRenderer(0,0)    #assuming (0,0) is in the renderer we are working on
        if (self._CurrentRenderer==None):
            return

        cam = self._CurrentRenderer.GetActiveCamera()

        # Get the view up (y) and view right (x) vectors
        view_up = plane_normal = view_right = plane_normal = zeros(3)

        cam.OrthogonalizeViewUp()
        view_up = cam.GetViewUp()
        self._vtkMath.Normalize(view_up)
        dir_proj = cam.GetDirectionOfProjection()
        plane_normal[0] = -dir_proj[0]
        plane_normal[1] = -dir_proj[1]
        plane_normal[2] = -dir_proj[2]
        self._vtkMath.Cross(view_up, plane_normal, view_right)
        self._vtkMath.Normalize(view_right)

        # GetLength gets the length of the diagonal of the bounding box
        stepsize = self._PickedActor.GetLength() / 200 * self._keyboardStepSize

        translation = zeros(3)

        keysym = self._iren.GetKeySym()

        if not(keysym):
            return
        if (keysym == "Left"):
            translation[0] = -stepsize * view_right[0]
            translation[1] = -stepsize * view_right[1]
            translation[2] = -stepsize * view_right[2]
        elif (keysym == "Right"):
            translation[0] = stepsize * view_right[0]
            translation[1] = stepsize * view_right[1]
            translation[2] = stepsize * view_right[2]
        elif (keysym == "Up"):
            translation[0] = stepsize * view_up[0]
            translation[1] = stepsize * view_up[1]
            translation[2] = stepsize * view_up[2]
        elif (keysym == "Down"):
            translation[0] = -stepsize * view_up[0]
            translation[1] = -stepsize * view_up[1]
            translation[2] = -stepsize * view_up[2]
        else:  #not a valid key press
            return

        self._PickedActor.AddPosition(translation)

        self.Render()


    def KeyboardZTransRotate(self):
        if (self._CurrentRenderer==None):    #CurrentRenderer can be None if there were no mouse interaction before
            self.FindPokedRenderer(0,0)            #assuming (0,0) is in the renderer we are working on
        if (self._CurrentRenderer==None):
            return
        cam = self._CurrentRenderer.GetActiveCamera()
        yaxis = cam.GetViewUp()
        zaxis = cam.GetViewPlaneNormal()
        xaxis = cross(yaxis,zaxis)

        #cam.GetDirectionOfProjection()
        #As of vtk5.0.3, inferred from the source code, direction of
        # projection is just the direction from camera posistion to
        # its focal point (before any oblique or ViewShear operation).
        # Therefore it is our Z(out-of-plane) axis.
        plane_normal = zeros(3)
        dir_proj = cam.GetDirectionOfProjection()
        plane_normal[0] = -dir_proj[0]
        plane_normal[1] = -dir_proj[1]
        plane_normal[2] = -dir_proj[2]
        self._vtkMath.Normalize(plane_normal)

        # GetLength gets the length of the diagonal of the bounding box
        stepsize =self._PickedActor.GetLength() / 50 * self._keyboardStepSize

        translation = zeros(3)
        scale = [1, 1, 1]

        keysym = self._iren.GetKeySym()

        if not(keysym):
            return
        if (keysym == "Left"):
            #spin counterclockwise
#            rotate =  [zeros(4),zeros(4)]
#            rotate[0][0] = self._rotStepSize * self._keyboardStepSize
#            rotate[0][1] = plane_normal[0]
#            rotate[0][2] = plane_normal[1]
#            rotate[0][3] = plane_normal[2]
#            self.Prop3DTransform(self._PickedActor, self._PickedActor.GetOrigin(),#GetCenter(),
#                1, rotate, scale)
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         zaxis[0],zaxis[1],zaxis[2])
        elif (keysym == "Right"):
            #spin clockwise
#            rotate =  [zeros(4),zeros(4)]
#            rotate[0][0] = -self._rotStepSize * self._keyboardStepSize
#            rotate[0][1] = plane_normal[0]
#            rotate[0][2] = plane_normal[1]
#            rotate[0][3] = plane_normal[2]
#            self.Prop3DTransform(self._PickedActor, self._PickedActor.GetOrigin(),#GetCenter(),
#                1, rotate, scale)
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         zaxis[0],zaxis[1],zaxis[2])
        elif (keysym == "Up"):
            #bring closer
            translation[0] = stepsize * plane_normal[0]
            translation[1] = stepsize * plane_normal[1]
            translation[2] = stepsize * plane_normal[2]
            self._PickedActor.AddPosition(translation)
        elif (keysym == "Down"):
            #push further
            translation[0] = -stepsize * plane_normal[0]
            translation[1] = -stepsize * plane_normal[1]
            translation[2] = -stepsize * plane_normal[2]
            self._PickedActor.AddPosition(translation)
        else:  #not a valid key press
            return

        if (self._AutoAdjustCameraClippingRange):
            self._CurrentRenderer.ResetCameraClippingRange()
        if (self._OffscreenWin2Img):
            self._OffscreenWin2Img.Modified()

        self._iren.Render()
    
    

#    def KeyboardRotate(self):
#        # rotate using the local coordinates, about the origin
#        keysym = self._iren.GetKeySym()
#        if not(keysym):
#            return
#        if (keysym == "Left"):
#          self._PickedActor.RotateY(-self._rotStepSize * self._keyboardStepSize)
#        elif (keysym == "Right"):
#          self._PickedActor.RotateY(self._rotStepSize * self._keyboardStepSize)
#        elif (keysym == "Up"):
#          self._PickedActor.RotateX(-self._rotStepSize * self._keyboardStepSize)
#        elif (keysym == "Down"):
#          self._PickedActor.RotateX(self._rotStepSize * self._keyboardStepSize)
#        else:  #not a valid key press
#            return
#        self._iren.Render()
   
    def KeyboardRotate(self):
        #print "Keyboard rotate"
        # rotate using the local coordinates, about the origin
        keysym = self._iren.GetKeySym()
        cam = self._CurrentRenderer.GetActiveCamera()
        yaxis = cam.GetViewUp()
        zaxis = cam.GetViewPlaneNormal()
        xaxis = cross(yaxis,zaxis)
        if not(keysym):
            return
        if (keysym == "Left"):
            # World Y axes
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         yaxis[0],yaxis[1],yaxis[2])
        elif (keysym == "Right"):
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         yaxis[0],yaxis[1],yaxis[2])
        elif (keysym == "Up"):
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         xaxis[0],xaxis[1],xaxis[2])
        elif (keysym == "Down"):
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         xaxis[0],xaxis[1],xaxis[2])
        else:  #not a valid key press
            return
        self._iren.Render()


    def Zoom(self,obj,event):
        if self._CurrentRenderer:
            x,y = obj.GetEventPosition()

            renderer = self._CurrentRenderer
            camera = self._CurrentCamera

            zoomFactor = pow(1.02,(0.5*(self._LastY - y)))
            self._CurrentZoom = self._CurrentZoom * zoomFactor

            if camera.GetParallelProjection():
                parallelScale = camera.GetParallelScale()/zoomFactor
                camera.SetParallelScale(parallelScale)
            else:
                camera.Dolly(zoomFactor)
                renderer.ResetCameraClippingRange()

            self._LastX = x
            self._LastY = y

            self.Render()


    def Dolly(self,obj,event):
        """
        vtkInteractorStyleTrackballActor.Dolly()
        The following are modified based on vtk 5.0.3's vtkInteractorStyleTrackballActor.
        The new code moves the object towards the camera, instead of in the direction
        from focal point to camera.
        The original function has several shortages:
            1. It relies on a properly-set FocalPoint. We cannot ignore the focal distance
            and just set the FocalPoint to be any point on the focal direction.
            2. Because the step size of the motion is uniform (i.e., depends on the focal
            distance instead of the distance of the object), when the object is far away,
            the visual(screen) size of the object changes very slow when the object is
            close to the camera, the screen size changes dramatically and the object can
            easily get behind the camera. The result of the new code is that the screen
            size of the object changes uniformly.
        """
        if ( self._OffscreenWin2Img):
                self._OffscreenWin2Img.Modified()

        if (self._CurrentRenderer == [] or self._PickedActor == []):
            return

        rwi = self._iren
        cam = self._CurrentRenderer.GetActiveCamera()

        view_point = zeros(3)
        motion_vector = zeros(3)

        view_point = cam.GetPosition()

        center = self._CurrentRenderer.GetCenter()

        dy = rwi.GetEventPosition()[1] - rwi.GetLastEventPosition()[1]
        yf = dy / center[1] * self._motionFactor
        dollyFactor = pow(1.03,yf) # instead of the vtk default of dollyFactor = pow(1.1, yf)

        dollyFactor -= 1.0

        obj_position = self._PickedActor.GetPosition()
        motion_vector[0] = (view_point[0] - obj_position[0]) * dollyFactor
        motion_vector[1] = (view_point[1] - obj_position[1]) * dollyFactor
        motion_vector[2] = (view_point[2] - obj_position[2]) * dollyFactor

        if (self._PickedActor.GetUserMatrix() != None):
            t = vtk.vtkTransform()
            t.PostMultiply()
            t.SetMatrix(self._PickedActor.GetUserMatrix())
            t.Translate(motion_vector[0], motion_vector[1], motion_vector[2])
            self._PickedActor.GetUserMatrix().DeepCopy(t.GetMatrix())
        else:
            self._PickedActor.AddPosition(motion_vector)

        if (self._AutoAdjustCameraClippingRange):
            self._CurrentRenderer.ResetCameraClippingRange()

        self.Render()


    def Spin(self):
        if ((self._CurrentRenderer == None) or (self._PickedActor == None)):
            return

        rwi = self._iren
        cam = self._CurrentRenderer.GetActiveCamera()

        """
         Get the axis to rotate around = vector from eye to origin
        -- end unmodified vtk code part 1--
        ... to be continued
         Origin of the model.
         To adef modifying "unmodified vtk code part 2", I did not change the
         variable name (vtkInteractorStyleTrackballActor used center of model).
        """

        obj_center = self._PickedActor.GetPosition()

        # --begin unmodified vtk code part 2--

        motion_vector = zeros(3)
        view_point = zeros(3)

        if (cam.GetParallelProjection()):
            # If parallel projection, wnat to get the view plane normal
            cam.ComputeViewPlaneNormal()
            motion_vector = cam.GetViewPlaneNormal
        else:
            # Perspective projection, get vector from eye to center of actor
            view_point = cam.GetPosition()
            motion_vector[0] = view_point[0] - obj_center[0]
            motion_vector[1] = view_point[1] - obj_center[1]
            motion_vector[2] = view_point[2] - obj_center[2]
            self._vtkMath.Normalize(motion_vector)

        disp_obj_center = zeros(3)

        self.ComputeWorldToDisplay(obj_center[0], obj_center[1], obj_center[2],
                                disp_obj_center)

        newAngle = atan2(rwi.GetEventPosition()[1] - disp_obj_center[1],
                         rwi.GetEventPosition()[0] - disp_obj_center[0])

        oldAngle = atan2(rwi.GetLastEventPosition()[1] - disp_obj_center[1],
                         rwi.GetLastEventPosition()[0] - disp_obj_center[0])

        newAngle *= self._vtkMath.DegreesFromRadians()
        oldAngle *= self._vtkMath.DegreesFromRadians()

        scale = zeros(3)

        scale[0] = scale[1] = scale[2] = 1.0

        rotate = [zeros(4),zeros(4)]

        rotate[0][0] = newAngle - oldAngle
        rotate[0][1] = motion_vector[0]
        rotate[0][2] = motion_vector[1]
        rotate[0][3] = motion_vector[2]

        self.Prop3DTransform(self._PickedActor, obj_center,1,rotate,scale)

        if (self._AutoAdjustClippingRange):
            self._CurrentRenderer.ResetCameraClippingRange()

        #-- end unmodified vtk code part 2--

        self.Render()


    def Reset(self,obj,event=None):
        if self._CurrentRenderer:
            self._CurrentRenderer.ResetCamera()

        self.Render()


    def SetProminentActor(self,actor):
        """
        Set the highlighted (i.e. current) actor.
        Only vtkActor support GetProperty(), not vtkProp3D.
        Return value: false if the actor is the same as the previous prominent actor.

        TODO: This needs to be checked to see if it works with Volume actor
        """

        #self.HighlightProp3D(actor)

        if (actor == None):
            return
            #self.HighlightProp3D(actor)

        oldactor = self._PickedActor

        if (oldactor):
            pass
            #TODO:DEBUG
            #print "Unselecting Old Actor"
            #oldactor.GetProperty().SetColor(1,0.20,0.0) #COLOR: orange
            # (actually fire red, but produces orange when combined with the yellow specular color)
            #oldactor.GetProperty().SetSpecularColor(1,1,0) #COLOR: yellow

        if (actor):
            pass
            #print "Selecting New Actor"
            #self.HighlightProp3D(actor)
            #self.Render()
            #actor.GetProperty().SetColor(0, 0.4, 1)  #  COLOR: sky blue (0, 0.58, 1)
            #actor.GetProperty().SetSpecularColor(0.8, 1, 1)

        return True


    def ClearProminentActor(self):
        SetProminentActor(None)


    def PickActor(self,obj,event):
        #print "in PickActor, CurrentRenderer:", self._CurrentRenderer
        if self._CurrentRenderer:
            x,y = self._iren.GetEventPosition()

            renderer = self._CurrentRenderer
            picker = self._Picker

            windowX, windowY = self._RenderWindow.GetSize()

            picker.Pick(x,y,0.0,renderer)

            path = picker.GetPath()

            if (path == None):
                #print "No actor picked"
                self.SetProminentActor(None)
                self._PickedActor = None
            else:
                self._PickedActor = path.GetFirstNode().GetViewProp()
                #print "Selecting actor...", type(self._PickedActor)
                self.SetProminentActor(self._PickedActor)

            self._iren.EndPickCallback()
            self.Render()


    def Prop3DTransform(self,prop3D,boxCenter,numRotation,rotate,scale):
        """
        Copied from vtkInteractorStyleTrackballActor.cpp, since it is protected,
        it cannot be accessed from python.
        """

        oldMatrix = prop3D.GetMatrix()

        orig = prop3D.GetOrigin()

        newTransform = vtk.vtkTransform()
        newTransform.PostMultiply()
        if (prop3D.GetUserMatrix() != None):
            newTransform.SetMatrix(prop3D.GetUserMatrix())
        else:
            newTransform.SetMatrix(oldMatrix)

        newTransform.Translate(-(boxCenter[0]), -(boxCenter[1]), -(boxCenter[2]))

        for i in range(0,numRotation):
            newTransform.RotateWXYZ(rotate[i][0], rotate[i][1],
                                 rotate[i][2], rotate[i][3])

        if ((scale[0] * scale[1] * scale[2]) != 0.0):
            newTransform.Scale(scale[0], scale[1], scale[2])

        newTransform.Translate(boxCenter[0], boxCenter[1], boxCenter[2])

        # now try to get the composit of translate, rotate, and scale
        newTransform.Translate(-(orig[0]), -(orig[1]), -(orig[2]))
        newTransform.PreMultiply()
        newTransform.Translate(orig[0], orig[1], orig[2])

        if (prop3D.GetUserMatrix() != None):
            newTransform.GetMatrix(prop3D.GetUserMatrix())
        else:
            prop3D.SetPosition(newTransform.GetPosition())
            prop3D.SetScale(newTransform.GetScale())
            prop3D.SetOrientation(newTransform.GetOrientation())

    
##    def HighlightProp3D(self,prop3D):
##        """
##        Reimplemented from C++ code
##        """
##
##        #no prop picked now
##        if ( not prop3D):
##
##        #was there previously?
##            if (self._PickedRenderer != None and self._OutlineActor):
##                self._PickedRenderer.RemoveActor(self._OutlineActor)
##                self._PickedRenderer = None
##
##
##        #prop picked now
##        else:
##
##            if ( not self._OutlineActor ):
##                # have to defer creation to get right type
##                self._OutlineActor = vtk.vtkActor()
##                self._OutlineActor.PickableOff()
##                self._OutlineActor.DragableOff()
##                self._OutlineActor.SetMapper(self._OutlineMapper)
##                self._OutlineActor.GetProperty().SetColor(self._PickColor)
##                self._OutlineActor.GetProperty().SetAmbient(1.0)
##                self._OutlineActor.GetProperty().SetDiffuse(0.0)
##
##
##            #check if picked in different renderer to previous pick
##            if (self._CurrentRenderer != self._PickedRenderer):
##
##                if (self._PickedRenderer != None and self._OutlineActor):
##
##                    self._PickedRenderer.RemoveActor(self._OutlineActor)
##
##            self._CurrentRenderer.AddActor(self._OutlineActor)
##            self._PickedRenderer = self._CurrentRenderer
##
##            self._Outline.SetBounds(prop3D.GetBounds())
##            #self.Render()


class QTJTInteractorStyle(JTInteractorStyle):
    """
    This class is designed to use with QT render windows, the one above is 
    for wx windows.  Most functions seem to work fine, but key events are 
    handled differently and need to be accounted for in the OnKeyDown function.
    """
    def __init__(self, iren=None):
        self._iren = iren
        #self._iren._key = None
        #self._iren._shift = False
        #self._iren._ctrl = False

        # initialize with an interactor so that the callbacks can be set.
        self._iren = iren
        if self._iren == None:
            print "Debug: style initialized without interactor."
        else:
             #if the interactor was specified, then set the callbacks
            self._RenderWindow = self._iren.GetRenderWindow()
            self.SetCallbacks()

        self._Picker = vtk.vtkPropPicker()
        self._vtkMath = vtk.vtkMath()
        self._PickedActor = None
        self._PickedProperty = vtk.vtkProperty()
        self._PickedProperty.SetColor(1,0,0)
        self._PrePickedProperty = None
        self._PickColor = (1,0,0)

        self._OutlineActor = None
        self._Outline = vtk.vtkOutlineSource()
        self._OutlineMapper = vtk.vtkPolyDataMapper()
        self._OutlineMapper.SetInput(self._Outline.GetOutput())

        self._keyboardStepSize = 1
        self._rotStepSize = 1
        self._motionFactor = 10 #VTK does not allow this property to be changed

        self._USE_X_CAPTURE = 0
        self._AutoAdjustCameraClippingRange = 0
        self._OffscreenWin2Img = None

        # these record the previous mouse position
        self._LastX = 0
        self._LastY = 0
        
        # the current interaction mode (Rotate, Pan, Zoom, etc)
        self._Mode = None
        self._ActiveButton = None

        # private attributes
        self.__OldFocus = None

        # used by the LOD actors
        self._DesiredUpdateRate = 1
        self._StillUpdateRate = 0.1
        

    def SetCallbacks(self):
#        self.RemoveAllObservers()
#        self._RenderWindow.RemoveAllObservers()
#        self._iren.RemoveAllObservers()
        self.AddObserver("LeftButtonPressEvent", self._OnButtonDown)
        self.AddObserver("LeftButtonReleaseEvent", self._OnButtonUp)
        self.AddObserver("MiddleButtonPressEvent", self._OnButtonDown)
        self.AddObserver("MiddleButtonReleaseEvent", self._OnButtonUp)
        self.AddObserver("RightButtonPressEvent", self._OnButtonDown)
        self.AddObserver("RightButtonReleaseEvent", self._OnButtonUp)
        #self.AddObserver("MouseMoveEvent", self.OnMotion)
        self.AddObserver("KeyPressEvent", self.OnKeyDown)
        self.AddObserver("KeyReleaseEvent", self.OnKeyUp)
        self.AddObserver("CharEvent", self.OnChar)

        
    def OnKeyDown(self,obj,event):
        # Grab key code values from QVTK interactor (obj is style)
#        print "QTJTInteractor (keynum, shift, ctrl, keycode): (%s,%s,%s,%s)" % \
#            (self._iren._key,self._iren._shift,self._iren._ctrl ,self._iren._keycode)

        # Change Keyboard Step size
        if (self._iren._keycode == '-'):
            self._keyboardStepSize *= 0.6
            print "Keyboard step size: %f" % self._keyboardStepSize
            return
        elif self._iren._keycode == '+':
            if ((self._keyboardStepSize / 0.6) < (self._RenderWindow.GetSize()[0]/2.0)):
                self._keyboardStepSize /= 0.6
            else:
                print "Keyboard step size limited to: %f" % self._RenderWindow.GetSize([0])/2.0
            print "Keyboard step size: %f" % self._keyboardStepSize
            return
        elif self._iren._keycode == '=':   #seems only US keyboard has = and + on the same key.
            if ((self._keyboardStepSize / 0.6) < (self._RenderWindow.GetSize()[0]/2.0)):
                self._keyboardStepSize /= 0.6
            else:
                print "Keyboard step size limited to: %f" % (self._RenderWindow.GetSize()[0]/2.0)
            print "Keyboard step size: %f" % self._keyboardStepSize
            return

        # Reset Camera *** WARNING *** this could invalidate a calibration!
        elif self._iren._keycode == 'r':
            #print "cannot reset view, calibration will be invalidated"
            self._CurrentRenderer.ResetCamera()
            print "Current camera positon: %s " % str(self._CurrentCamera.GetPosition())
            self._CurrentCamera.SetClippingRange(1,3000)
            return

        # Pick actor under the cursor
        elif self._iren._keycode == 'p':
            self.PickActor(obj,event)
            return
        
        # Pick actor under the cursor
        elif self._iren._keycode == 'w':
            if isinstance(self._PickedActor,JT.SurfaceModel):
                prop = self._PickedActor.GetProperty()
                prop.SetRepresentationToWireframe()
                self.Render()
            return
        # Pick actor under the cursor
        elif self._iren._keycode == 's':
            if isinstance(self._PickedActor,JT.SurfaceModel):
                prop = self._PickedActor.GetProperty()
                prop.SetRepresentationToSurface()
                self.Render()
            return
        
        # reset the center of rotation of the actor
        elif self._iren._keycode == 'c':
            I = np.eye(4)
            orientation = self._PickedActor.GetOrientation()
            position = self._PickedActor.GetPosition()
            self._PickedActor.SetUserMatrix(JT.utils.GetVTKMatrixFromNumpyArray(I))
            self._PickedActor.SetOrientation(0,0,0)
            center = np.asarray(self._PickedActor.GetCenter()) - \
                     np.asarray(self._PickedActor.GetPosition())
            self._PickedActor.SetOrigin(center)
            self._PickedActor.SetOrientation(orientation)
            self._PickedActor.SetPosition(position)
            print "Reset center to: %s" % str(center)
            return

        # Close the render window
        elif self._iren._keycode == 'e':
            print 'Not Exiting interaction with keypress'
            #self._iren.ExitCallback()

        # Some debug actions
        elif self._iren._key == 68: #d
            if self._iren._ctrl:
                if self._PickedActor:
                    print "Actor: ", self._PickedActor
            else:
                print "Camera: ", self._CurrentRenderer.GetActiveCamera()

        # Interactively change the volume color
        # This will only work for volume actors
        # 'l' alone will increase the set point, Ctrl+'l' will decrease
        elif self._iren._key == 76: #l
            # Opacity can be set on volumes and surface models
            if self._PickedActor != None:
                self.KeyboardSetOpacityLevel(self._iren._ctrl)
                self._iren.Render()

        # Interactively change the volume opacity threshold
        # This will only work for volume actors
        # 't' alone will increase the set point, Ctrl+'t' will decrease
        elif self._iren._key == 84: #t
            # Threshold can only be set on volumes
            if isinstance(self._PickedActor,JT.Volume):
                if self._PickedActor != None:
                    self.KeyboardSetOpacityThreshold(self._iren._ctrl)
                    self._iren.Render()
        # Print Help
        elif self._iren._key ==72:
            self.PrintHelp()

        # Keyboard interaction
        if self._PickedActor != None:
            #print "keyboard positioning of actor"
            if ((self._iren._key == LEFT) or (self._iren._key == UP) or 
                (self._iren._key == RIGHT) or (self._iren._key == DOWN)):
#            if ((self._key == "Left") or (self._key == "Up") or 
#                (self._key == "Right") or (self._key == "Down")):
                if (self._iren._shift):
                    self.KeyboardZTransRotate()
                elif (self._iren._ctrl):
                    self.KeyboardRotate()
                else:
                    self.KeyboardTranslate()

                #self.HighlightProp3D(self._PickedActor)
        # Hichlight the volumee using different colors
        if self._iren._key == 49:#1
            print "set color (1,0,0)"
            self._PickedActor.SetColor((1,0,0))
            self.Render()
        if self._iren._key == 50:#2
            print "set color (0,1,0)"
            self._PickedActor.SetColor((0,1,0)) 
            self.Render() 
        if self._iren._key == 51:#3
            print "set color (0,0,1)"
            self._PickedActor.SetColor((0,0,1))
            self.Render()    
        if self._iren._key == 52:#4
            print "set color (0,0,0)"
            self._PickedActor.SetColor((0,0,0)) 
            self.Render()
        if self._iren._key == 53:#5
            print "set color (1,1,1)"
            self._PickedActor.SetColor((1,1,1))
            self.Render()
        if self._iren._key == 54:#6
            print "set color UF Blue!"
            self._PickedActor.SetColor((0, 33.0/255.0, 165.0/255.0))
            self.Render()
        if self._iren._key == 55:#7
            print "set color UF Orange!"
            self._PickedActor.SetColor((255.0/255.0, 74.0/255.0, 0))
            self.Render()
            

    def OnLeftDown(self,obj,event):
        if not self._Mode:
            if self._iren._ctrl:
                self._Mode = "Zoom"
            elif self._iren._shift:
                self._Mode = "Pan"
            else:
                self._Mode = "Rotate"

        self._iren.StartPickCallback()
        self._iren.EndPickCallback()

        self.PickActor(obj,event)
    
    def UpdateRenderer(self,obj,event):
        """
        UpdateRenderer will identify the renderer under the mouse and set
        up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
        """
        #print obj
        x,y = obj._iren.GetEventPosition()
        #TODO: Debug
        #print "in UpdateRenderer, event position (x,y):", x,y

        windowX, windowY = self._RenderWindow.GetSize()

        renderers = self._RenderWindow.GetRenderers()
        numRenderers = renderers.GetNumberOfItems()

        self._CurrentRenderer = None
        renderers.InitTraversal()
        for i in range(0,numRenderers):
            renderer = renderers.GetNextItem()
            vx,vy = (0,0)
            if (windowX > 1):
                vx = float(x)/(windowX-1)
            if (windowY > 1):
                vy = (windowY-float(y)-1)/(windowY-1)
            (vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()

            if (vx >= vpxmin and vx <= vpxmax and
                vy >= vpymin and vy <= vpymax):
                self._CurrentRenderer = renderer
                self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
                                        +vpxmin
                self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
                                        +vpymin
                self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
                lights = self._CurrentRenderer.GetLights()
                lights.InitTraversal()
                self._CurrentLight = lights.GetNextItem()
                break

        self._LastX = x
        self._LastY = y



    def KeyboardTranslate(self):
        #print "Keyboard translate"
        if (self._CurrentRenderer==None):    #CurrentRenderer can be None if there were no mouse interaction before
            self.FindPokedRenderer(0,0)    #assuming (0,0) is in the renderer we are working on
        if (self._CurrentRenderer==None):
            return

        cam = self._CurrentRenderer.GetActiveCamera()

        # Get the view up (y) and view right (x) vectors
        view_up = plane_normal = view_right = plane_normal = zeros(3)

        cam.OrthogonalizeViewUp()
        view_up = cam.GetViewUp()
        self._vtkMath.Normalize(view_up)
        dir_proj = cam.GetDirectionOfProjection()
        plane_normal[0] = -dir_proj[0]
        plane_normal[1] = -dir_proj[1]
        plane_normal[2] = -dir_proj[2]
        self._vtkMath.Cross(view_up, plane_normal, view_right)
        self._vtkMath.Normalize(view_right)

        # GetLength gets the length of the diagonal of the bounding box
        stepsize = self._PickedActor.GetLength() / 200 * self._keyboardStepSize

        translation = zeros(3)

        keynum = self._iren._key

        if not(keynum):
            return
        if (keynum == LEFT):
            # LEFT
            translation[0] = -stepsize * view_right[0]
            translation[1] = -stepsize * view_right[1]
            translation[2] = -stepsize * view_right[2]
        elif (keynum == RIGHT):
            # RIGHT
            translation[0] = stepsize * view_right[0]
            translation[1] = stepsize * view_right[1]
            translation[2] = stepsize * view_right[2]
        elif (keynum == UP):
            # UP
            translation[0] = stepsize * view_up[0]
            translation[1] = stepsize * view_up[1]
            translation[2] = stepsize * view_up[2]
        elif (keynum == DOWN):
            # DOWN
            translation[0] = -stepsize * view_up[0]
            translation[1] = -stepsize * view_up[1]
            translation[2] = -stepsize * view_up[2]
        else:  #not a valid key press
            return

        self._PickedActor.AddPosition(translation)

        self.Render()
        
    def KeyboardRotate(self):
        #print "Keyboard rotate"
        # rotate using the local coordinates, about the origin
        keynum = self._iren._key
        cam = self._CurrentRenderer.GetActiveCamera()
        yaxis = cam.GetViewUp()
        zaxis = cam.GetViewPlaneNormal()
        xaxis = cross(yaxis,zaxis)
        if not(keynum):
            return
        if (keynum == LEFT):
            # World Y axes
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         yaxis[0],yaxis[1],yaxis[2])
        elif (keynum == RIGHT):
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         yaxis[0],yaxis[1],yaxis[2])
        elif (keynum == UP):
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         xaxis[0],xaxis[1],xaxis[2])
        elif (keynum == DOWN):
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         xaxis[0],xaxis[1],xaxis[2])
        else:  #not a valid key press
            return
        self._iren.Render()
    
    def KeyboardZTransRotate(self):
        #print "Keyboard ztrans rotate"
        if (self._CurrentRenderer==None):    #CurrentRenderer can be None if there were no mouse interaction before
            self.FindPokedRenderer(0,0)            #assuming (0,0) is in the renderer we are working on
        if (self._CurrentRenderer==None):
            return
        cam = self._CurrentRenderer.GetActiveCamera()
        yaxis = cam.GetViewUp()
        zaxis = cam.GetViewPlaneNormal()
        xaxis = cross(yaxis,zaxis)
        #cam.GetDirectionOfProjection()
        #As of vtk5.0.3, inferred from the source code, direction of
        # projection is just the direction from camera position to
        # its focal point (before any oblique or ViewShear operation).
        # Therefore it is our Z(out-of-plane) axis.
        plane_normal = zeros(3)
        dir_proj = cam.GetDirectionOfProjection()
        plane_normal[0] = -dir_proj[0]
        plane_normal[1] = -dir_proj[1]
        plane_normal[2] = -dir_proj[2]
        self._vtkMath.Normalize(plane_normal)

        # GetLength gets the length of the diagonal of the bounding box
        stepsize =self._PickedActor.GetLength() / 20 * self._keyboardStepSize

        translation = zeros(3)
        scale = [1, 1, 1]

        keynum = self._iren._key

        if not(keynum):
            return
        if (keynum == LEFT):
            #spin counterclockwise
            self._PickedActor.RotateWXYZ(self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         zaxis[0],zaxis[1],zaxis[2])
        elif (keynum == RIGHT):
            #spin clockwise
            self._PickedActor.RotateWXYZ(-self._rotStepSize * \
                                         self._keyboardStepSize,\
                                         zaxis[0],zaxis[1],zaxis[2])
        elif (keynum == UP):
            #bring closer
            translation[0] = stepsize * plane_normal[0]
            translation[1] = stepsize * plane_normal[1]
            translation[2] = stepsize * plane_normal[2]
            self._PickedActor.AddPosition(translation)
        elif (keynum == DOWN):
            #push further
            translation[0] = -stepsize * plane_normal[0]
            translation[1] = -stepsize * plane_normal[1]
            translation[2] = -stepsize * plane_normal[2]
            self._PickedActor.AddPosition(translation)
        else:  #not a valid key press
            return

        if (self._AutoAdjustCameraClippingRange):
            self._CurrentRenderer.ResetCameraClippingRange()
        if (self._OffscreenWin2Img):
            self._OffscreenWin2Img.Modified()

        self._iren.Render()


class QTJTInteractorStyleImage(vtk.vtkInteractorStyleImage):
    def __init__(self):
        #print "JT image style"
        #self.drr = QTJTInteractorStyle(iren)
        # For DRR interaction
        self._keyboardStepSize = 1
        self._rotStepSize = 1
        
        
        
    
                



#----------------------------------------------------------------------------
def myVTKRenderWindowConeExample():

    """Like it says, just a simple example
    """

    # This example introduces the concepts of user interaction with VTK.
    # First, a different interaction style (than the default) is defined.
    # Second, the interaction is started.
    #
    #
    #
    # Next we create an instance of vtkConeSource and set some of its
    # properties. The instance of vtkConeSource "cone" is part of a visualization
    # pipeline (it is a source process object) it produces data (output type is
    # vtkPolyData) which other filters may process.
    #
    cone = vtk.vtkConeSource()
    cone.SetHeight( 3.0 )
    cone.SetRadius( 1.0 )
    cone.SetResolution( 30 )

    #
    # In this example we terminate the pipeline with a mapper process object.
    # (Intermediate filters such as vtkShrinkPolyData could be inserted in
    # between the source and the mapper.)  We create an instance of
    # vtkPolyDataMapper to map the polygonal data into graphics primitives. We
    # connect the output of the cone souece to the input of this mapper.
    #
    coneMapper = vtk.vtkPolyDataMapper()
    coneMapper.SetInputConnection(cone.GetOutputPort())

    #
    # Create an actor to represent the cone. The actor orchestrates rendering of
    # the mapper's graphics primitives. An actor also refers to properties via a
    # vtkProperty instance, and includes an internal transformation matrix. We
    # set this actor's mapper to be coneMapper which we created above.
    #
    coneActor = vtk.vtkActor()
    coneActor.SetMapper(coneMapper)

    #
    # Create the Renderer and assign actors to it. A renderer is like a
    # viewport. It is part or all of a window on the screen and it is responsible
    # for drawing the actors it has.  We also set the background color here.
    #
    ren1 = vtk.vtkRenderer()
    ren1.AddActor(coneActor)
    ren1.SetBackground(0.1, 0.2, 0.4)

    #
    # Finally we create the render window which will show up on the screen
    # We put our renderer into the render window using AddRenderer. We also
    # set the size to be 300 pixels by 300.
    #
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(ren1)
    renWin.SetSize(512, 512)

    #
    # The vtkRenderWindowInteractor class watches for events (e.g., keypress,
    # mouse) in the vtkRenderWindow. These events are translated into
    # event invocations that VTK understands (see VTK/Common/vtkCommand.h
    # for all events that VTK processes). Then observers of these VTK
    # events can process them as appropriate.
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    #
    # By default the vtkRenderWindowInteractor instantiates an instance
    # of vtkInteractorStyle. vtkInteractorStyle translates a set of events
    # it observes into operations on the camera, actors, and/or properties
    # in the vtkRenderWindow associated with the vtkRenderWinodwInteractor.
    # Here we specify a particular interactor style.
    #style = vtk.vtkInteractorStyleTrackballCamera()
    style = JTInteractorStyle(iren)
    iren.SetInteractorStyle(style)

    #
    # Unlike the previous scripts where we performed some operations and then
    # exited, here we leave an event loop running. The user can use the mouse
    # and keyboard to perform the operations on the scene according to the
    # current interaction style.
    #

    #
    # Initialize and start the event loop. Once the render window appears, mouse
    # in the window to move the camera. The Start() method executes an event
    # loop which listens to user mouse and keyboard events. Note that keypress-e
    # exits the event loop. (Look in vtkInteractorStyle.h for a summary of events, or
    # the appropriate Doxygen documentation.)
    #
    iren.Initialize()
    iren.Start()

def QVTKRenderWidgetConeExample():    
    """A simple example that uses the QVTKRenderWindowInteractor class."""

    # every QT app needs an app
    app = QtGui.QApplication(['QVTKRenderWindowInteractor'])

    # create the widget
    mainWindow = QtGui.QMainWindow()
    frame = QtGui.QFrame()
    layout = QtGui.QGridLayout()
    frame.setLayout(layout)
    mainWindow.setCentralWidget(frame)
    widget = QVTKRenderWindowInteractor(frame)
    label1 = QtGui.QLabel(frame)
    label2 = QtGui.QLabel(frame)
    layout.addWidget(widget,0,0,1,1)
    layout.addWidget(label1,1,0,1,1)
    layout.addWidget(label2,2,0,1,1)
    label1.setText(QtCore.QString("<font color=red>Testing</font>"))
    label2.setText(QtCore.QString("Testing2"))
    # if you dont want the 'q' key to exit comment this.
    widget.AddObserver("ExitEvent", lambda o, e, a=app: a.quit())

    ren = vtk.vtkRenderer()
    widget.GetRenderWindow().AddRenderer(ren)
    style = QTJTInteractorStyle(widget)
    widget.SetInteractorStyle(style)
    

    cone = vtk.vtkConeSource()
    cone.SetResolution(30)

    coneMapper = vtk.vtkPolyDataMapper()
    coneMapper.SetInput(cone.GetOutput())

    coneActor = vtk.vtkActor()
    coneActor.SetMapper(coneMapper)

    ren.AddActor(coneActor)
    ren.SetBackground(0.1, 0.2, 0.4)
    
    def updateLabel(obj,event):
        position = coneActor.GetPosition()
        angle = coneActor.GetOrientation()
        text1 = str("<font color=red>(%4.2f,%4.2f,%4.2f)</font>" % \
                              (position[0],position[1],position[2]))
        text2 = str("<font color=green>(%4.2f,%4.2f,%4.2f)</font>" % \
                              (angle[0],angle[1],angle[2]))
        label1.setText(text1)
        label2.setText(text2)
    
    widget.AddObserver("KeyPressEvent",updateLabel)

    widget.Initialize()
    widget.Start()
    # show the widget
    mainWindow.show()
    # start event processing
    app.exec_()

if __name__ == "__main__":
    #myVTKRenderWindowConeExample()
    QVTKRenderWidgetConeExample()


